package org.az.netty_study.p12_协议;

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.logging.LoggingHandler;

import java.net.InetSocketAddress;

/**
 * 所谓无规矩不成方圆，当客户端与服务端通信时，必须约定好，一方发送的数据必须是什么什么格式，然后另一方按照这个格式解析就可以得到正确的数据
 * 这个约定就是协议
 * 在redis中，使用"set name hahaha"时，实际发送给redis服务端的数据格式如下:
 * *3     表示这条完整的命令有三个部分
 * $3     表示第一个部分三个字节
 * set    表示第一部分的数据，也就是set
 * $4     表示接下来的数据有四个字节
 * name   接收四个字节的数据，也就是name
 * $6     表示接下来的数据有四个字节
 * hahaha 接收六个字节的数据，也就是hahaha
 * 上面的7行，就是"set name hahaha"，每行以回车分割
 */
public class _1_Redis的协议 {
    public static void main(String[] args) throws InterruptedException {
        /**
         * 连接redis服务端，连接成功后，就触发入站handler的channelActive方法
         * 该方法中，按照协议写入数据，set name nana!!
         * 写入后，可以打开redis可视化工具执行"get name"看看有没有写入成功
         */
        EventLoopGroup group = new NioEventLoopGroup();
        Bootstrap client = new Bootstrap()
                .group(group)
                .channel(NioSocketChannel.class)
                .handler(new ChannelInitializer<NioSocketChannel>() {
                    @Override
                    protected void initChannel(NioSocketChannel ch) throws Exception {
                        ch.pipeline().addLast(new LoggingHandler());
                        ch.pipeline().addLast(new ChannelInboundHandlerAdapter(){
                            @Override
                            public void channelActive(ChannelHandlerContext ctx) throws Exception {
                                ByteBuf buf = ctx.alloc().buffer();
                                buf.writeBytes("*3\r\n".getBytes());
                                buf.writeBytes("$3\r\n".getBytes());
                                buf.writeBytes("set\r\n".getBytes());
                                buf.writeBytes("$4\r\n".getBytes());
                                buf.writeBytes("name\r\n".getBytes());
                                buf.writeBytes("$6\r\n".getBytes());
                                buf.writeBytes("nana!!\r\n".getBytes());
                                ctx.writeAndFlush(buf);
                            }

                            //给redis服务端发送一条命令后，服务端会给客户端发送命令的执行结果
                            @Override
                            public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                                System.out.println(msg.toString());
                                ctx.channel().close();
                            }
                        });
                    }
                });
        ChannelFuture channelFuture = client.connect(new InetSocketAddress("192.168.1.208", 6379));
        channelFuture.sync();
        channelFuture.channel().closeFuture().addListener(ch -> {
            group.shutdownGracefully();
        });
    }
}
